package com.bl.student.service.biz.pay.impl;

import com.bl.student.common.ApiResponseCode;
import com.bl.student.common.CommonServiceException;
import com.bl.student.common.enums.GoodsType;
import com.bl.student.common.enums.PayBusinessType;
import com.bl.student.common.enums.PayStatus;
import com.bl.student.common.utils.DateUtils;
import com.bl.student.common.utils.EncodeUtils;
import com.bl.student.common.utils.JSONUtil;
import com.bl.student.common.utils.OkHttpHelper;
import com.bl.student.dao.model.*;
import com.bl.student.dao.redis.model.UserInfo;
import com.bl.student.dao.repository.*;
import com.bl.student.service.biz.BaseService;
import com.bl.student.service.biz.id.IdService;
import com.bl.student.service.biz.pay.PayService;
import com.bl.student.service.biz.vip.VipService;
import com.bl.student.service.vo.apply.ApplyVo;
import com.bl.student.service.vo.pay.*;
import com.bl.student.tp.alipay.app.AlipayAppPayApi;
import com.bl.student.tp.alipay.app.AlipayAppPayRequest;
import com.bl.student.tp.wxpay.app.*;
import com.google.common.base.Optional;
import com.google.common.collect.Maps;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.bl.student.common.enums.pay.WechatPayPayInfoVo;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import static com.bl.student.common.ApiResponseCode.APP_PAY_FAILED;

/**
 * Created by yujingyi on 2018/4/14.
 */
@Service
@Log4j2
public class PayServiceImpl extends BaseService implements PayService {

    static final private String PRODUCT_CODE = "QUICK_MSECURITY_PAY";
    static final private String DISABLE_PAY_CHANNELS = "creditCard";

    @Autowired
    PayRepository payRepository;

    @Autowired
    IdService idService;

    @Autowired
    ApplyRepository applyRepository;

    @Autowired
    TaskRepository taskRepository;

    @Autowired
    GoodsRepository goodsRepository;

    @Autowired
    PayService payService;

    @Autowired
    VipService vipService;

    @Autowired
    TeacherRepository teacherRepository;

    @Autowired
    AlipayAppPayApi alipayAppPayApi;

    @Autowired
    WechatPayAppApi wechatPayAppApi;

    @Autowired
    UserRepository userRepository;

    @Override
    @Transactional
    public PayEntity getPayInfo(String amount, String payer, PayBusinessType payBusinessType, String applyId) {
        String tradeNo = idService.getTradeNo();
        PayEntity payEntity = new PayEntity();
        payEntity.setTradeNo(tradeNo);
        payEntity.setStatus(PayStatus.PAYING);
        payEntity.setCreateTime(System.currentTimeMillis());
        payEntity.setPayer(payer);
        ApplyEntity applyEntity = applyRepository.findOne(applyId);
        payEntity.setUserId(applyEntity.getPartybId());
        payEntity.setAmount(amount);
        payEntity.setBusinessType(payBusinessType);
        payEntity.setApplyId(applyId);

        payRepository.save(payEntity);

        return payEntity;
    }

    @Override
    @Transactional
    public void handlePayInfo(String tradeNo, UserInfo userInfo ,PayStatus payStatus) {
        PayEntity payEntity = payRepository.findOne(tradeNo);
        if (!payEntity.getPayer().equals(userInfo.getId())) {
            throwCommonServiceException(ApiResponseCode.DATA_INCORRECT);
        }
        payEntity.setStatus(payStatus);
        payRepository.save(payEntity);
    }

    @Override
    public AlipayPayInfoVo getVipAlipayAppPayInfo(UserInfo userInfo, String goodsId) {

        GoodsEntity goodsEntity = goodsRepository.findOne(goodsId);
        if (goodsEntity == null ) {
            throwCommonServiceException(ApiResponseCode.DATA_INCORRECT);
        }

//        double initialAmount = goodsEntity.getPoint().doubleValue();
        double initialAmount = 121222.23;
        String amount = String.valueOf(initialAmount / 100);
        PayEntity payEntity = payService.getPayInfo(((int) (initialAmount)) + "", userInfo.getId(), PayBusinessType.ALIPAY, goodsId);

        Map<String, Object> passBackParams = Maps.newHashMap();
        passBackParams.put("id", userInfo.getId());
        passBackParams.put("goodsId", goodsEntity.getId());
        AlipayAppPayRequest.BizContent bizContent = AlipayAppPayRequest.BizContent.builder()
                .out_trade_no(payEntity.getTradeNo())
                .subject(goodsEntity.getTitle())
                .product_code(PRODUCT_CODE)
                .total_amount(amount)
                .disable_pay_channels(DISABLE_PAY_CHANNELS)
                .passback_params(EncodeUtils.urlEncode(OkHttpHelper.parseFormParams(passBackParams)))
                .build();

        AlipayAppPayRequest alipayAppPayRequest = AlipayAppPayRequest.builder().build();
        alipayAppPayRequest.setBiz_content(JSONUtil.jsonEncode(bizContent));

        String orderStr = alipayAppPayApi.getAppPayInfo(alipayAppPayRequest);

        AlipayPayInfoVo alipayPayInfoVo = AlipayPayInfoVo.builder()
                .orderStr(orderStr)
                .build();

        return alipayPayInfoVo;
    }

    @Override
    @Transactional
    public void syncAlipayResult(AlipaySyncResultRequest alipaySyncResultRequest, UserInfo userInfo) {
        AlipaySyncResultRequest.Response response = alipaySyncResultRequest.getAlipay_trade_app_pay_response();

        if (!alipaySyncResultRequest.isSuccess()) {
            throw new CommonServiceException(APP_PAY_FAILED.getCode(), response.getMsg());
        }

//        String alipayId = alipayAppPayNotifyRequest.getBuyer_id();
        String tradeNo = response.getOut_trade_no();
        String amount = response.getTotal_amount();

        // update pay info
        payService.handlePayInfo(tradeNo, userInfo, PayStatus.SUCCESS);
    }


    @Override
    public WechatPayPayInfoVo getWechatPayAppPayInfo(UserInfo userInfo, String applyId) {
        TeacherEntity teacherEntity = teacherRepository.findOne(userInfo.getId());

        ApplyEntity applyEntity = applyRepository.findOne(applyId);
        if (applyEntity == null ) {
            throwCommonServiceException(ApiResponseCode.DATA_INCORRECT);
        }
        double initialAmount = applyEntity.getMoney().doubleValue() * 100;
//        double initialAmount = 12232.23;
        String amount = String.valueOf(initialAmount / 100);
        PayEntity payEntity = payService.getPayInfo(((int) (initialAmount)) + "", userInfo.getId(), PayBusinessType.WECHAT, applyId);

        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(DateUtils.FORMAT_YYYYMMDDHHMMSS);
        WechatPayUnifiedOrderRequest wechatPayUnifiedOrderRequest = WechatPayUnifiedOrderRequest.builder()
                .body(applyEntity.getTaskId())
                .out_trade_no(payEntity.getTradeNo())
                .total_fee((int) (initialAmount))
                .time_start(simpleDateFormat.format(payEntity.getCreateTime()))
                .spbill_create_ip("192.168.0.1")
                .device_info(userInfo.getSId())
                .openid(teacherEntity.getOpenId())
                .build();

        Optional<WechatPayUnifiedOrderResponse> wechatPayUnifiedOrderResponseOptional = wechatPayAppApi.getUnifiedOrder(wechatPayUnifiedOrderRequest);
        if (!wechatPayUnifiedOrderResponseOptional.isPresent()) {
            throw new CommonServiceException(ApiResponseCode.GET_PRE_PAY_INFO_FAILED.getCode(),
                    ApiResponseCode.GET_PRE_PAY_INFO_FAILED.getMsg());
        }
        WechatPayUnifiedOrderResponse wechatPayUnifiedOrderResponse = wechatPayUnifiedOrderResponseOptional.get();

        WechatPayPayInfoVo wechatPayPayInfoVo = wechatPayAppApi.getAppPayInfo(wechatPayUnifiedOrderResponse.getPrepay_id());
        wechatPayPayInfoVo.setOutTradeNo(payEntity.getTradeNo());

        return wechatPayPayInfoVo;
    }

    @Override
    public WechatPayPayInfoVo getWechatPayAppPayInfo(UserInfo userInfo, String money, String subject) {
        return null;
    }


    @Override
    public void updateWechatPayAppPayInfoSync(WechatPaySyncResultRequest wechatPaySyncResultRequest, UserInfo userInfo) {
        String tradeNo = wechatPaySyncResultRequest.getOutTradeNo();

        // update pay info
        payService.handlePayInfo(tradeNo, userInfo, PayStatus.SUCCESS);

    }

    @Override
    public PayListVo getPayAndApplyList(String userId,Pageable pageable, String type){
        PayListVo payListVo = new PayListVo();
        List<PayOfApplyVo>  payOfApplyVos = new ArrayList<>();

        Page<PayEntity> payEntities = null;
        if ("PARTYA".equals(type)) {
            payEntities = payRepository.findByPayer(userId, pageable);
        } else {
            payEntities = payRepository.findByUserId(userId, pageable);
        }

        for(PayEntity payEntity:payEntities) {
//            PayStatus sta = payEntity.getStatus();
            if ("PARTYB".equals(type)) {
                ApplyEntity applyEntity = applyRepository.findOne(payEntity.getApplyId());
                TaskEntity taskEntity = taskRepository.findOne(applyEntity.getTaskId());
                if (taskEntity.getStatus().equals("FINISH")) {
                    if (PayStatus.SUCCESS == payEntity.getStatus()) {
                        String applyId = payEntity.getApplyId();
                        PayOfApplyVo payOfApplyVo = new PayOfApplyVo();

                        ApplyVo applyVo = new ApplyVo();

                        BeanUtils.copyProperties(applyEntity, applyVo);

                        String partyaId = applyEntity.getPartyaId();
                        TeacherEntity teacherEntity = teacherRepository.findOne(partyaId);
                        applyVo.setPartyaNickname(teacherEntity.getNickname());
                        applyVo.setPartyaMobile(teacherEntity.getMobile());
                        applyVo.setPartyaAvatar(teacherEntity.getAvatar());

                        String partybId = applyEntity.getPartybId();
                        UserEntity userEntity = userRepository.findOne(partybId);
                        applyVo.setPartybNickname(userEntity.getNickname());
                        applyVo.setPartybMobile(userEntity.getMobile());
                        applyVo.setPartybAvatar(userEntity.getAvatar());
                        payOfApplyVo.setApplyVo(applyVo);
                        payOfApplyVo.setPayEntity(payEntity);
                        payOfApplyVos.add(payOfApplyVo);
                    }
                }
            } else {
                if (PayStatus.SUCCESS == payEntity.getStatus()) {
                    String applyId = payEntity.getApplyId();
                    PayOfApplyVo payOfApplyVo = new PayOfApplyVo();
                    ApplyEntity applyEntity = new ApplyEntity();
                    applyEntity = applyRepository.findOne(applyId);

                    ApplyVo applyVo = new ApplyVo();

                    BeanUtils.copyProperties(applyEntity, applyVo);

                    String partyaId = applyEntity.getPartyaId();
                    TeacherEntity teacherEntity = teacherRepository.findOne(partyaId);
                    applyVo.setPartyaNickname(teacherEntity.getNickname());
                    applyVo.setPartyaMobile(teacherEntity.getMobile());
                    applyVo.setPartyaAvatar(teacherEntity.getAvatar());

                    String partybId = applyEntity.getPartybId();
                    UserEntity userEntity = userRepository.findOne(partybId);
                    applyVo.setPartybNickname(userEntity.getNickname());
                    applyVo.setPartybMobile(userEntity.getMobile());
                    applyVo.setPartybAvatar(userEntity.getAvatar());
                    payOfApplyVo.setApplyVo(applyVo);
                    payOfApplyVo.setPayEntity(payEntity);
                    payOfApplyVos.add(payOfApplyVo);
                }
            }
        }
        payListVo.setTotalCount(payOfApplyVos.size());
        payListVo.setList(payOfApplyVos);
        return payListVo;
    }

    @Override
    public PayListVo getPayAndApplyListManager(String userId, String payer, String status, String applyId, Pageable pageable) {

        PayListVo payListVo = new PayListVo();
        List<PayOfApplyVo>  payOfApplyVos = new ArrayList<>();

        Page<PayEntity> payEntities = null;
        payEntities = payRepository.findMultList(userId, payer, status, applyId, pageable);

        for(PayEntity payEntity:payEntities) {

                String applyId0 = payEntity.getApplyId();
                PayOfApplyVo payOfApplyVo = new PayOfApplyVo();
                ApplyEntity applyEntity = new ApplyEntity();

                applyEntity = applyRepository.findOne(applyId0);

                ApplyVo applyVo = new ApplyVo();

                BeanUtils.copyProperties(applyEntity, applyVo);

                String partyaId = applyEntity.getPartyaId();
                TeacherEntity teacherEntity = teacherRepository.findOne(partyaId);
                applyVo.setPartyaNickname(teacherEntity.getNickname());
                applyVo.setPartyaMobile(teacherEntity.getMobile());
                applyVo.setPartyaAvatar(teacherEntity.getAvatar());

                String partybId = applyEntity.getPartybId();
                UserEntity userEntity = userRepository.findOne(partybId);
                applyVo.setPartybNickname(userEntity.getNickname());
                applyVo.setPartybMobile(userEntity.getMobile());
                applyVo.setPartybAvatar(userEntity.getAvatar());

                payOfApplyVo.setApplyVo(applyVo);
                payOfApplyVo.setPayEntity(payEntity);
                payOfApplyVos.add(payOfApplyVo);

        }
        payListVo.setTotalCount(payOfApplyVos.size());
        payListVo.setList(payOfApplyVos);
        return payListVo;
    }

}
